/**
 * @file STL_Digest.h
 * @author Derek Liu (yjkhtddx@sina.com)
 * @brief 
 * @version 0.1
 * @date 2020-12-29
 * 
 * @copyright Copyright Sci-Tech Laboratories (c) 2020
 * 
 */

#ifndef __STL_DIGEST_H__
#define __STL_DIGEST_H__

#include <string>
#include <vector>
#include <map>
#include "STL_Tools.h"
#include "STL_MD5.h"
#include "STL_Base64.h"

namespace STL
{
    class STL_Digest
    {
    public:
        typedef struct UserInfo_t
        {
            std::string username;
            std::string password;
        } UserInfo;
        STL_SYNTHESIZE(std::string, m_realm, Realm);           //服务器端
        STL_SYNTHESIZE(std::string, m_privateKey, PrivateKey); //服务器端
        STL_SYNTHESIZE(std::string, m_eTag, ETag);             //服务器端
        STL_SYNTHESIZE(int, m_timeout, Timeout);               //服务器端
    public:
        STL_Digest();
        ~STL_Digest();

    public: //服务器端
        void addUserInfo(UserInfo info);
        void delUserInfo(UserInfo info);
        UserInfo getUserInfo(std::string username);
        bool checkNonce(std::string nonce);
        bool checkAuthenticate(
            std::string username,
            std::string password,
            std::string method,
            std::string uri,
            std::string body,
            std::string realm,
            std::string nonce,
            std::string nc,
            std::string algorithm,
            std::string cnonce,
            std::string qop,
            std::string response);
        std::string getMessageForWWWAuthenticate(bool stale); //WWW-Authenticate //服务器端
        std::string getMessageForAuthenticationInfo(
            std::string username,
            std::string password,
            std::string uri,
            std::string body,
            std::string realm,
            std::string nc,
            std::string algorithm,
            std::string qop,
            std::string cnonce); //Authentication-Info //服务器端
    private:
        std::vector<UserInfo> m_userList;

    public:
        static std::string genDigestContent(std::map<std::string, std::string> map, std::string head);
        static std::map<std::string, std::string> parseDigestContent(std::string content);
        static std::string genDigest(
            std::string username,
            std::string password,
            std::string method,
            std::string uri,
            std::string body,
            std::string realm,
            std::string nonce,
            std::string nc,
            std::string algorithm,
            std::string cnonce,
            std::string qop);
        static std::string genNonce(std::string eTag, std::string privateKey);
        static std::string genCnonce();
        static std::string genOpaque();
        static std::string getNonceCount(int count);
        static std::string getSupportQop(std::string qop);

    public: //客户端 //注意 stale字段如果为true，表示过期，需要重新计算
        /**
         * @brief Get the Message For Authenticate object
         * 
         * @param username 必填
         * @param password 必填
         * @param method 必填
         * @param uri 必填
         * @param body qop=auth-int时 必填
         * @param realm 必填
         * @param nonce 必填
         * @param nonceCount qop!=""时 必填
         * @param algorithm 可选
         * @param cnonce algorithm=md5-sess时 必填
         * @param qop qop!=""时 必填
         * @param opaque 透传参数 可选
         * @return std::string 
         */
        static std::string getMessageForAuthenticate(
            std::string username,
            std::string password,
            std::string method,
            std::string uri,
            std::string body,
            std::string realm,
            std::string nonce,
            int nonceCount,
            std::string algorithm,
            std::string cnonce,
            std::string qop,
            std::string opaque); //Authenticate 客户端使用
        static std::string getMessageForBasicAuthenticate(std::string username, std::string password,std::string realm = "")
        {
            //TODO 确定realm没有用
            std::string ret = std::string("Basic ");
            ret = ret + base64Encode(username + ":" + password);
            return ret;
        };
    };
} // namespace STL

#endif //__STL_DIGEST_H__